import 'dart:async';

import 'package:flutter/material.dart';
import 'package:ideology/shared/widgets/file_explorer/file_explorer_theme_data.dart';
import 'package:ideology/shared/widgets/file_explorer/utils/default_file_color.dart';

import 'file_explorer_controller.dart';
import 'file_node.dart';
import 'internal/auto_refresh_mixin.dart';
import 'internal/delete_service.dart';
import 'internal/expanded_ensure.dart';
import 'internal/file_explorer_manager.dart';
import 'internal/fs_gateway.dart';
import 'internal/path_resolver.dart';
import 'internal/rename_service.dart';
import 'widgets/file_explorer_list_view.dart';

/// # FileExplorer
///
/// 文件资源管理器主组件（Stateful）
///
/// - 以树形结构展示 [roots]，支持懒加载、展开/收起、选择、打开、删除、重命名；
/// - 通过 [FileExplorerController] 管理 UI 状态（展开项、选中项、缓存的子节点等）；
/// - 业务交互通过回调上抛（onNodeSelect / onNodeOpen / onNodeDelete）；
/// - 与真实文件系统的交互通过内部服务（DeleteService / RenameService + FsGateway）完成；
/// - 可通过 [realPathResolver] 将“逻辑路径”映射到真实文件系统路径；
/// - 支持自动刷新（定时拉取已展开节点的子节点）；
/// - 主题由 [FileExplorerThemeData] 控制。
class FileExplorer extends StatefulWidget {
  /// 根节点集合。每个 [FileNode] 是树的起点。
  final List<FileNode> roots;

  /// 节点被选中时的回调。
  /// - [path]：所选节点的逻辑路径
  /// - [node]：对应节点
  final void Function(String path, FileNode node)? onNodeSelect;

  /// 节点被“打开”时的回调（通常针对文件）。
  /// - [path]：逻辑路径
  /// - [node]：对应节点
  final void Function(String path, FileNode node)? onNodeOpen;

  /// 节点删除成功后的回调（业务侧处理，如审计日志等）。
  /// - [path]：逻辑路径
  /// - [node]：对应节点
  final void Function(String path, FileNode node)? onNodeDelete;

  /// 是否在初始时展开所有根节点（只作用于文件夹根）。
  final bool initiallyExpandedRoots;

  /// 外观/行为主题（背景色、行高、动画时长、图标颜色等）。
  final FileExplorerThemeData theme;

  /// 文件名 → 颜色 的解析器；未提供则使用 [defaultFileColor]。
  final Color Function(String fileName)? fileColorResolver;

  /// 可选的外部控制器；不传则内部创建。
  final FileExplorerController? controller;

  /// 可选的外部滚动控制器；不传则内部创建。
  final ScrollController? scrollController;

  /// 真实路径解析回调：
  /// 当 [FileNode.fullPath] 为空时，会调用此回调将 UI 逻辑路径
  /// （如 "111/project copy.cloud"）转换为文件系统绝对路径。
  final String Function(String logicalPath, FileNode node)? realPathResolver;

  const FileExplorer({
    super.key,
    required this.roots,
    required this.theme,
    this.onNodeSelect,
    this.onNodeOpen,
    this.onNodeDelete,
    this.initiallyExpandedRoots = false,
    this.fileColorResolver,
    this.controller,
    this.scrollController,
    this.realPathResolver,
  });

  @override
  State<FileExplorer> createState() => _FileExplorerState();
}

/// FileExplorer 的内部状态类。
///
/// 主要职责：
/// - 初始化/持有控制器与各类服务；
/// - 监听控制器的可观察状态并触发刷新；
/// - 定时（通过 [AutoRefreshMixin]）对已展开节点进行“强制重载”子节点；
/// - 处理打开/展开/选择/删除/重命名等事件，并维护缓存一致性。
class _FileExplorerState extends State<FileExplorer>
    with AutoRefreshMixin<FileExplorer> {
  late final FileExplorerController _ctl;
  late final FileExplorerManager _manager;

  // —— 抽离后的服务 —— //
  late final PathResolver _pathResolver; // 逻辑路径 → 真实路径
  late final DeleteService _deleter;     // 删除服务
  late final RenameService _renamer;     // 重命名服务
  final ExpandedNodesEnsurer _ensurer = ExpandedNodesEnsurer(); // 展开项可见性保障

  ScrollController? _internalScroll;

  /// 自动刷新周期（用于拉取已展开节点的最新子节点）
  @override
  Duration get refreshInterval => const Duration(seconds: 2);

  /// 统一获取滚动控制器：优先使用外部传入，否则用内部创建的
  ScrollController get sc => widget.scrollController ?? _internalScroll!;

  @override
  void initState() {
    super.initState();

    // 控制器：外部提供则复用，否则内部创建
    _ctl = widget.controller ?? FileExplorerController();
    _manager = FileExplorerManager(_ctl);

    // 注入路径解析与本地文件系统网关
    _pathResolver = PathResolver(external: widget.realPathResolver);
    final fs = LocalFileSystemGateway();

    // 初始化删除/重命名服务（内部将使用 pathResolver 与 fs）
    _deleter = DeleteService(
      pathResolver: _pathResolver,
      fs: fs,
    );

    _renamer = RenameService(
      pathResolver: _pathResolver,
      fs: fs,
    );

    // 根据配置：初始展开所有“根级文件夹”
    if (widget.initiallyExpandedRoots && _ctl.expanded.value.isEmpty) {
      final next = {..._ctl.expanded.value};
      for (final n in widget.roots) {
        if (n.isFolder) next.add(n.name);
      }
      _ctl.expanded.value = next;
    }

    // 监听控制器的状态，变化时刷新 UI
    _ctl.expanded.addListener(_onExpandedChanged);
    _ctl.selectedPath.addListener(_onNonStructuralChanged);
    _ctl.loading.addListener(_onNonStructuralChanged);
    _ctl.childrenRevision.addListener(_onNonStructuralChanged);

    // 若未提供外部滚动控制器，则内部创建一个
    if (widget.scrollController == null) {
      _internalScroll = ScrollController();
    }
  }

  @override
  void dispose() {
    // 解绑监听，释放资源
    _ctl.expanded.removeListener(_onExpandedChanged);
    _ctl.selectedPath.removeListener(_onNonStructuralChanged);
    _ctl.loading.removeListener(_onNonStructuralChanged);
    _ctl.childrenRevision.removeListener(_onNonStructuralChanged);
    _internalScroll?.dispose();
    super.dispose();
  }

  /// 自动刷新钩子：定时遍历“已展开”的路径，对可懒加载的节点进行强制重载。
  @override
  void onAutoRefresh() async {
    if (!mounted) return;
    for (final path in _ctl.expanded.value) {
      final node = _manager.findNodeByPath(widget.roots, path);
      if (node == null || !node.canLazyLoad) continue;
      await _manager.loadChildrenForNode(node, path, forceReload: true);
    }
  }

  /// 展开集合变化回调：
  /// - 刷新 UI
  /// - 调度“展开项可见性保障”（确保展开后的目标在可视区域内可见）
  void _onExpandedChanged() {
    if (mounted) setState(() {});
    _ensurer.schedule(ctl: _ctl, roots: widget.roots, manager: _manager);
  }

  /// 非结构性（选中、加载中、修订号）变化回调：仅刷新 UI
  void _onNonStructuralChanged() {
    if (mounted) setState(() {});
  }

  // ========== 事件处理 ==========

  /// 打开事件：若为文件（非文件夹）才触发外部回调。
  void _handleOpen(String path, FileNode node) {
    if (!node.isFolder) widget.onNodeOpen?.call(path, node);
  }

  /// 展开/收起事件：
  /// - 更新控制器中的“展开集合”
  /// - 若收起：清除该路径及其后代的缓存与版本
  /// - 若展开且可懒加载：触发一次强制加载子节点
  Future<void> _handleToggle(FileNode node, String path) async {
    final expanding = !_ctl.expanded.value.contains(path);
    _ctl.setExpanded(path, expanding);

    if (!expanding) {
      // 收起：清理缓存与版本
      _ctl.loadedChildren.removeWhere(
            (k, _) => k == path || k.startsWith('$path/'),
      );
      _ctl.childrenRevision.value++;
      _manager.clearVersionFor(path);
    } else if (node.canLazyLoad) {
      // 展开：懒加载/强制刷新子节点
      await _manager.loadChildrenForNode(node, path, forceReload: true);
    }
  }

  /// 选中事件：更新控制器并上抛回调。
  void _handleSelect(String path, FileNode node) {
    _ctl.selectedPath.value = path;
    widget.onNodeSelect?.call(path, node);
  }

  /// 删除事件：
  /// - 调用删除服务执行真实删除
  /// - 成功则更新缓存、清理选中、版本号+1，并触发外部回调
  /// - 失败则弹出 SnackBar
  Future<void> _handleDelete(String path, FileNode node) async {
    final ok = await _deleter.delete(path, node);
    if (!ok) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('删除失败：真实路径解析失败、无权限或文件不存在')),
        );
      }
      return; // 删除失败，不更新 UI
    }

    // 业务侧回调（可记录审计日志等）
    widget.onNodeDelete?.call(path, node);

    // —— 删除成功后，更新 UI/缓存 —— //
    final int idx = path.lastIndexOf('/');
    if (idx == -1) {
      // 根级节点：直接从 roots 移除
      widget.roots.removeWhere((n) => identical(n, node));
    } else {
      // 非根：从父路径的缓存中移除
      final parentPath = path.substring(0, idx);
      final origin = _ctl.loadedChildren[parentPath];
      if (origin != null) {
        final growable = List<FileNode>.from(origin); // 确保可变
        growable.removeWhere((n) => identical(n, node));
        _ctl.loadedChildren[parentPath] = growable;
      }
    }

    // 清除被删节点及其后代的缓存
    _ctl.loadedChildren.removeWhere(
          (k, _) => k == path || k.startsWith('$path/'),
    );

    // 如果当前选中项位于被删节点之下，也一并清除选中
    if (_ctl.selectedPath.value == path ||
        (_ctl.selectedPath.value?.startsWith('$path/') ?? false)) {
      _ctl.selectedPath.value = null;
    }

    // bump 修订号 & 清版本
    _ctl.childrenRevision.value++;
    _manager.clearVersionFor(path);
    if (mounted) setState(() {});
  }

  /// 重命名事件：
  /// - 调用重命名服务
  /// - 成功后同步更新缓存中的节点名称、选中路径、修订号与版本
  /// - 失败时弹出 SnackBar 并返回 false
  Future<bool> _handleRename(String path, FileNode node, String newName) async {
    final ok = await _renamer.rename(
      logicalPath: path,
      node: node,
      newName: newName,
    );
    if (!ok) {
      // 失败原因通常是：真实路径解析失败 或 同名冲突
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('重命名失败：已存在同名或路径不可解析')),
        );
      }
      return false;
    }

    // —— 重命名成功：更新缓存与选中 —— //
    // 计算父逻辑路径
    final int idx = path.lastIndexOf('/');
    final String parentLogical =
    (idx == -1) ? node.name : path.substring(0, idx);

    // 在缓存或静态 children 中替换该节点为“同构但改名”的新节点
    final list = _ctl.loadedChildren[parentLogical]?.toList() ??
        _manager.findNodeByPath(widget.roots, parentLogical)?.children.toList() ??
        <FileNode>[];

    final i = list.indexWhere((n) => identical(n, node) || n.name == node.name);
    if (i >= 0) {
      // 基于 FileNode 的构造签名，创建仅改名的新实例
      list[i] = FileNode(
        newName,
        isFolder: node.isFolder,
        fullPath: node.fullPath, // 若希望强制走 resolver，可置为 null（此处保持逻辑不变）
        loader: node.loader,
        children: node.children,
      );
      _ctl.cacheChildren(parentLogical, list);
    }

    // 更新选中路径到新逻辑路径
    final newLogicalPath =
    (idx == -1) ? newName : '${path.substring(0, idx)}/$newName';
    _ctl.select(newLogicalPath);

    // bump 修订号 & 清版本 & 刷新 UI
    _ctl.childrenRevision.value++;
    _manager.clearVersionFor(path);
    if (mounted) setState(() {});

    return true;
  }

  // ========== children 工具 ==========

  /// 返回一个“无参函数”，在调用时拿到路径 [p] 对应的 children：
  /// - 优先使用缓存 [_ctl.loadedChildren[p]]
  /// - 否则回退为节点自身的静态 children
  List<FileNode> Function() _getChildrenFor(FileNode n, String p) =>
          () => _ctl.loadedChildren[p] ?? n.children;

  /// 立即解析并返回路径 [p] 对应的 children（同步）：
  /// - 优先使用缓存
  /// - 否则回退为节点自身的静态 children
  List<FileNode> _resolveChildren(FileNode n, String p) =>
      _ctl.loadedChildren[p] ?? n.children;

  @override
  Widget build(BuildContext context) {
    final t = widget.theme;

    return Container(
      color: t.backgroundColor,
      child: Column(
        children: [
          Expanded(
            child: FileExplorerListView(
              roots: widget.roots,
              ctl: _ctl,
              theme: t,
              scrollController: sc,
              getChildrenFor: _getChildrenFor,
              resolveChildren: _resolveChildren,
              onToggle: _handleToggle,
              onSelect: _handleSelect,
              onOpen: _handleOpen,
              onDelete: _handleDelete,
              onRename: _handleRename,
              fileColorResolver:
              widget.fileColorResolver ?? (n) => defaultFileColor(n, t),
              realPathResolver: widget.realPathResolver,
            ),
          ),
        ],
      ),
    );
  }
}
